
MovingPandas provides a trajectory datatype based on GeoPandas. The project home is at https://github.com/anitagraser/movingpandas
The documentation is available at https://movingpandas.readthedocs.io/en/master/
import pandas as pd
import geopandas as gpd
from geopandas import GeoDataFrame, read_file
import shapely as shp
from shapely.geometry import Point, LineString, Polygon
from datetime import datetime, timedelta
import movingpandas as mpd
import hvplot.pandas
import warnings
warnings.filterwarnings('ignore')
print(f'MovingPandas version {mpd.__version__}')
print(f'GeoPandas version {gpd.__version__}')
print(f'Shapely version {shp.__version__}')
MovingPandas version 0.8.rc1 GeoPandas version 0.10.2 Shapely version 1.7.1
Trajectory objects consist of a trajectory ID and a GeoPandas GeoDataFrame with a DatetimeIndex. The data frame therefore represents the trajectory data as a Pandas time series with associated point locations (and optional further attributes).
Let's create a small toy trajectory to see how this works:
df = pd.DataFrame([
{'geometry':Point(0,0), 't':datetime(2018,1,1,12,0,0)},
{'geometry':Point(6,0), 't':datetime(2018,1,1,12,6,0)},
{'geometry':Point(6,6), 't':datetime(2018,1,1,12,10,0)},
{'geometry':Point(9,9), 't':datetime(2018,1,1,12,15,0)}
]).set_index('t')
gdf = GeoDataFrame(df, crs=31256)
toy_traj = mpd.Trajectory(gdf, 1)
toy_traj
Trajectory 1 (2018-01-01 12:00:00 to 2018-01-01 12:15:00) | Size: 4 | Length: 16.2m Bounds: (0.0, 0.0, 9.0, 9.0) LINESTRING (0 0, 6 0, 6 6, 9 9)
toy_traj.plot()
<AxesSubplot:>
We can also access the trajectory's GeoDataFrame:
toy_traj.df
| geometry | |
|---|---|
| t | |
| 2018-01-01 12:00:00 | POINT (0.000 0.000) |
| 2018-01-01 12:06:00 | POINT (6.000 0.000) |
| 2018-01-01 12:10:00 | POINT (6.000 6.000) |
| 2018-01-01 12:15:00 | POINT (9.000 9.000) |
toy_traj.df.plot()
<AxesSubplot:>
df = pd.read_csv('../data/geolife_small.csv', delimiter=';')
df
| X | Y | fid | id | sequence | trajectory_id | tracker | t | |
|---|---|---|---|---|---|---|---|---|
| 0 | 116.391305 | 39.898573 | 1 | 1 | 1 | 1 | 19 | 2008-12-11 04:42:14+00 |
| 1 | 116.391317 | 39.898617 | 2 | 2 | 2 | 1 | 19 | 2008-12-11 04:42:16+00 |
| 2 | 116.390928 | 39.898613 | 3 | 3 | 3 | 1 | 19 | 2008-12-11 04:43:26+00 |
| 3 | 116.390833 | 39.898635 | 4 | 4 | 4 | 1 | 19 | 2008-12-11 04:43:32+00 |
| 4 | 116.389410 | 39.898723 | 5 | 5 | 5 | 1 | 19 | 2008-12-11 04:43:47+00 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 5903 | 116.337194 | 39.926232 | 6993 | 6993 | 867 | 5 | 2 | 2009-02-25 14:31:04+00 |
| 5904 | 116.337207 | 39.926237 | 6994 | 6994 | 868 | 5 | 2 | 2009-02-25 14:31:09+00 |
| 5905 | 116.337259 | 39.926207 | 6995 | 6995 | 869 | 5 | 2 | 2009-02-25 14:31:14+00 |
| 5906 | 116.337290 | 39.926201 | 6996 | 6996 | 870 | 5 | 2 | 2009-02-25 14:31:19+00 |
| 5907 | 116.337332 | 39.926186 | 6997 | 6997 | 871 | 5 | 2 | 2009-02-25 14:31:24+00 |
5908 rows × 8 columns
traj_collection = mpd.TrajectoryCollection(df, 'trajectory_id', t='t', x='X', y='Y')
print(traj_collection)
TrajectoryCollection with 5 trajectories
traj_collection.plot(column='trajectory_id', legend=True, figsize=(9,5))
<AxesSubplot:>
gdf = read_file('../data/geolife_small.gpkg')
gdf
| id | sequence | trajectory_id | tracker | t | geometry | |
|---|---|---|---|---|---|---|
| 0 | 1 | 1 | 1 | 19 | 2008-12-11 04:42:14+00 | POINT (116.39131 39.89857) |
| 1 | 2 | 2 | 1 | 19 | 2008-12-11 04:42:16+00 | POINT (116.39132 39.89862) |
| 2 | 3 | 3 | 1 | 19 | 2008-12-11 04:43:26+00 | POINT (116.39093 39.89861) |
| 3 | 4 | 4 | 1 | 19 | 2008-12-11 04:43:32+00 | POINT (116.39083 39.89863) |
| 4 | 5 | 5 | 1 | 19 | 2008-12-11 04:43:47+00 | POINT (116.38941 39.89872) |
| ... | ... | ... | ... | ... | ... | ... |
| 5903 | 6993 | 867 | 5 | 2 | 2009-02-25 14:31:04+00 | POINT (116.33719 39.92623) |
| 5904 | 6994 | 868 | 5 | 2 | 2009-02-25 14:31:09+00 | POINT (116.33721 39.92624) |
| 5905 | 6995 | 869 | 5 | 2 | 2009-02-25 14:31:14+00 | POINT (116.33726 39.92621) |
| 5906 | 6996 | 870 | 5 | 2 | 2009-02-25 14:31:19+00 | POINT (116.33729 39.92620) |
| 5907 | 6997 | 871 | 5 | 2 | 2009-02-25 14:31:24+00 | POINT (116.33733 39.92619) |
5908 rows × 6 columns
After reading the trajectory point data from file, we want to construct the trajectories.
traj_collection = mpd.TrajectoryCollection(gdf, 'trajectory_id', t='t')
print(traj_collection)
TrajectoryCollection with 5 trajectories
traj_collection.plot(column='trajectory_id', legend=True, figsize=(9,5))
<AxesSubplot:>
traj_collection.plot()
<AxesSubplot:>
my_traj = traj_collection.trajectories[1]
print(my_traj)
Trajectory 2 (2009-06-29 07:02:25 to 2009-06-29 11:13:12) | Size: 897 | Length: 38764.6m Bounds: (116.319212, 39.971703, 116.592616, 40.082514) LINESTRING (116.590957 40.071961, 116.590905 40.072007, 116.590879 40.072027, 116.590915 40.072004,
my_traj.plot(linewidth=5, capstyle='round', figsize=(9,3))
<AxesSubplot:>
To visualize trajectories in their geographical context, we can also create interactive plots with basemaps:
my_traj.hvplot(width=500, height=300, line_width=7.0, tiles='OSM')